%{

#include <stdio.h>
#include <stdlib.h>

extern int yylex();
extern int yyparse();
extern FILE* yyin;

void yyerror(const char* s);

#include "ast.h"

struct ast *root;

%}

%union {
	int ival;
	float fval;
	char *name;
	struct ast *node;
}

%token<ival> T_INT8 T_INT10 T_INT16
%token<fval> T_FLOAT
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT
%token T_GT T_LT T_EQ
%token<name> T_IDENT
%token T_SEMI T_LEFT_BR T_RIGHT_BR
%token T_IF T_THEN T_ELSE T_WHILE T_DO
%token T_NEWLINE T_QUIT
%left T_PLUS T_MINUS
%left T_MULTIPLY T_DIVIDE

// %type<ival> expression
// %type<fval> mixed_expression
%type <node> P L S C E T F I

%start P

%%

P:
	| L			{printf("P->L\n"); $$ = newast(P_L, NULL, $1, NULL); root = $$;}
	| L P		{printf("P->L P\n"); $$ = newast(P_LP, NULL, $1, NULL); root = $$;}
;

L: S T_SEMI		{printf("L->S;\n"); $$ = newast(L_SS, NULL, $1, NULL);}
;

S: I T_EQ E					{printf("S->I = E\n"); $$ = newast(S_IEE, $1, NULL, $3);}
	| T_IF C T_THEN S				{printf("S->if C then S\n"); $$ = newast(S_IT, $2, $4, NULL);}
	| T_WHILE C T_DO S				{printf("S->while C do S\n"); $$ = newast(S_WD, $2, NULL, $4);} //kdkdkdk
	| T_IF C T_THEN S T_ELSE S		{printf("S->if C then S else S\n"); $$ = newast(S_ITE, $2, $4, $6);}
	| T_LEFT_BR S T_RIGHT_BR		{printf("S->{ S }\n"); $$ = newast(S_LPR, NULL, $2, NULL);}
;

C: E T_GT E			{printf("C->E1>E2\n"); $$ = newast(C_EGE, $1, NULL, $3);}
	| E T_LT E		{printf("C->E1<E2\n"); $$ = newast(C_ELE, $1, NULL, $3);}
	| E T_EQ E		{printf("C->E1=E2\n"); $$ = newast(C_EEE, $1, NULL, $3);}
;

E: E T_PLUS T			{printf("E->E+T\n"); $$ = newast(E_EAT, $1, NULL, $3);}
	| E T_MINUS T		{printf("E->E-T\n"); $$ = newast(E_EST, $1, NULL, $3);}
	| T					{printf("E->T\n"); $$ = newast(E_T, NULL, $1, NULL);}
;

T: F						{printf("T->F\n"); $$ = newast(T_F, NULL, $1, NULL);}
	| T T_MULTIPLY F		{printf("T->T*F\n"); $$ = newast(T_TMF, $1, NULL, $3);}
	| T T_DIVIDE F			{printf("T->T/F\n"); $$ = newast(T_TDF, $1, NULL, $3);}
;

F: T_LEFT E T_RIGHT		{printf("F->(E)\n"); $$ = newast(F_LER, NULL, $2, NULL);}
	| I					{printf("F->I\n"); $$ = newast(F_I, NULL, $1, NULL);}
	| T_INT8			{printf("F->int8\n"); $$ = newfint(F_I8, $1);}
	| T_INT10			{printf("F->int10\n"); $$ = newfint(F_I10, $1);}
	| T_INT16			{printf("F->int16\n"); $$ = newfint(F_I16, $1);}
	| T_FLOAT			{printf("F->float\n"); $$ = newffloat(F_F, $1);}
;

I: T_IDENT				{printf("I->id\n"); $$ = newident(I_I, $1);}
;

%%

int main() {

	yyin = stdin;

	do {
		yyparse();
	} while(!feof(yyin));
	
	printf("\n\n");
	printast(stdout, root);
	return 0;
}

void yyerror(const char* s) {
	fprintf(stderr, "Parse error: %s\n", s);
	exit(1);
}
